package com.yloveg.shiro;
 
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
 
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;

import com.yloveg.entity.SUserRole;
import com.yloveg.entity.Suser;
import com.yloveg.service.SUserRoleService;
import com.yloveg.service.UserService;

 
/**
 * @todo 自定义 Realm,查询数据库并返回正确的数据
 * @author Hans
 * @time 2018下午6:11:20
 *
 */
public class UserRealm extends AuthorizingRealm{
	
    @Autowired
    private UserService userService;
    
    @Autowired
    private SUserRoleService sUserRoleService;
 
	@Autowired
	private Suser us;
 
	/**
	 * @see 授权，在配有缓存的情况下，只加载一次。
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {
		//当前登录用户，账号
		String userCode = principal.toString();
		System.out.println("当前登录用户:"+userCode);
		//获取角色信息
		List<Map<String, Object>> roleList = new ArrayList<Map<String, Object>>();
		roleList = null;
		Set<String> roles = new HashSet<String>();
		
		if(roleList.size()>0){
			for(Map<String, Object> role : roleList){
				roles.add(String.valueOf(role.get("rcode")));
			}
		}else{
			System.out.println("当前用户没有角色！");
		}
		
		SimpleAuthorizationInfo info = null;
		info = new SimpleAuthorizationInfo(roles);
		return info;
	}
	
	/**
	 * @see 认证登录，查询数据库，如果该用户名正确，得到正确的数据，并返回正确的数据
	 * 		AuthenticationInfo的实现类SimpleAuthenticationInfo保存正确的用户信息
	 *    
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		//1.将token转换为UsernamePasswordToken
		UsernamePasswordToken userToken = (UsernamePasswordToken)token;
		//2.获取token中的登录账户
		String userCode = userToken.getUsername();
		//3.查询数据库，是否存在指定的用户名和密码的用户(主键/账户/密码/账户状态/盐)
		us = null;
		us = userService.findUserByNameAndPassword(userCode);
		//4.1 如果没有查询到，抛出异常
		if( us == null ) {
			throw new UnknownAccountException("账户"+userCode+"不存在！");
		}
		if( us.getState() == 0){
			throw new LockedAccountException(us.getUsername()+"被锁定！");
		}
		//4.2 如果查询到了，封装查询结果，
		Object principal = us.getUsername();
		Object credentials = us.getPassword();
		String realmName = this.getName();
		String salt = "123456";
		//获取盐，用于对密码在加密算法(MD5)的基础上二次加密ֵ
		ByteSource byteSalt = ByteSource.Util.bytes(salt);
		SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal, credentials, byteSalt, realmName);
		//5. 返回给调用login(token)方法
		return info;
	}
 
}
